<template>
  <div class="app-container">
    <!-- ✅ 管理员切换用户（仅管理员显示） -->
    <el-card v-if="isAdmin" class="mb-4" shadow="never">
      <el-form :inline="true">
        <el-form-item label="查看用户">
          <el-select
            v-model="selectedViewUserId"
            placeholder="选择要查看的用户"
            @change="handleUserSwitch"
            style="width: 250px"
            clearable
          >
            <el-option
              v-for="user in usersWithTasks"
              :key="user.user_id"
              :label="`${user.nick_name || user.user_name} (${user.user_name})`"
              :value="user.user_id"
            />
          </el-select>
          <el-tag v-if="selectedViewUserId" type="info" style="margin-left: 10px">
            当前查看：{{ getCurrentViewUserName() }}
          </el-tag>
        </el-form-item>
      </el-form>
    </el-card>
    
    <!-- 折叠容器 -->
    <el-collapse v-model="activeCollapse" class="mb-4">
      <!-- 任务配置区 -->
      <el-collapse-item name="taskConfig">
        <template #title>
          <span style="font-weight: 600;">
            <el-icon style="margin-right: 8px;"><Setting /></el-icon>
            搜索任务配置
          </span>
          <!-- ✅ 调整：把任务控制按钮放到title区域，收起面板也能看到 -->
          <!-- ✅ 管理员查看其他用户时，隐藏操作按钮 -->
          <div v-if="!isAdmin || !selectedViewUserId" style="margin-left: 12px;">
            <el-button type="primary" @click.stop="handleSaveConfig" icon="DocumentChecked" size="small">
              保存配置
            </el-button>
            <el-button
              type="success"
              @click.stop="handleStartTask"
              icon="VideoPlay"
              :disabled="taskStatus === 'running'"
              size="small"
            >
              启动任务
            </el-button>
            <el-button
              type="danger"
              @click.stop="handleStopTask"
              icon="VideoPause"
              :disabled="taskStatus !== 'running'"
              size="small"
            >
              停止任务
            </el-button>
          </div>
        </template>

        <el-form :model="taskConfig" :inline="true" label-width="100px">
        <el-form-item label="搜索关键词">
          <el-input
            v-if="!isAdmin || !selectedViewUserId"
            v-model="taskConfig.keyword"
            placeholder="请输入搜索关键词"
            style="width: 200px"
            clearable
          />
          <span v-else style="width: 200px; display: inline-block; color: #606266; padding: 0 11px; line-height: 32px;">
            {{ taskConfig.keyword || '-' }}
          </span>
        </el-form-item>
        
        <el-form-item label="价格区间">
          <template v-if="!isAdmin || !selectedViewUserId">
            <el-input
              v-model="taskConfig.min_price"
              placeholder="最低价"
              type="number"
              min="0"
              style="width: 110px"
              @change="onMinPriceChange"
            />
            <span style="margin: 0 8px;">-</span>
            <el-input
              v-model="taskConfig.max_price"
              placeholder="最高价"
              type="number"
              min="0"
              style="width: 110px"
              @change="onMaxPriceChange"
            />
          </template>
          <span v-else style="color: #606266; line-height: 32px;">
            {{ taskConfig.min_price || '-' }} - {{ taskConfig.max_price || '-' }}
          </span>
        </el-form-item>
        
        <el-form-item label="下单价格">
          <el-input
            v-if="!isAdmin || !selectedViewUserId"
            v-model="taskConfig.order_price"
            placeholder="0=所有新商品都下单"
            style="width: 180px"
            type="number"
            min="0"
            @change="onOrderPriceChange"
          >
            <template #append>元</template>
          </el-input>
          <span v-else style="color: #606266; padding: 0 11px; line-height: 32px;">
            {{ taskConfig.order_price || 0 }} 元
          </span>
        </el-form-item>
        
        <el-form-item label="搜索间隔">
          <el-input
            v-if="!isAdmin || !selectedViewUserId"
            v-model="taskConfig.total_time"
            placeholder="总时间"
            style="width: 120px"
            type="number"
            min="1"
          >
            <template #append>秒</template>
          </el-input>
          <span v-else style="color: #606266; padding: 0 11px; line-height: 32px;">
            {{ taskConfig.total_time || '-' }} 秒
          </span>
        </el-form-item>
        
        <el-form-item label="自动下单">
          <el-switch
            v-if="!isAdmin || !selectedViewUserId"
            v-model="taskConfig.enable_auto_order"
            active-text="开启"
            inactive-text="关闭"
          />
          <span v-else style="color: #606266; line-height: 32px;">
            {{ taskConfig.enable_auto_order ? '开启' : '关闭' }}
          </span>
        </el-form-item>
        
        <el-form-item style="margin-left: 16px;">
          <template #label>
            <span style="display: inline-flex; align-items: center; white-space: nowrap;">
              <span>首次搜索不下单</span>
              <el-tooltip content="开启后，首次搜索发现的新商品不会自动下单，避免长时间后启动任务出现大量新商品下单" placement="top">
                <el-icon style="margin-left: 4px; cursor: pointer; color: #909399; font-size: 14px;">
                  <QuestionFilled />
                </el-icon>
              </el-tooltip>
            </span>
          </template>
          <el-switch
            v-if="!isAdmin || !selectedViewUserId"
            v-model="taskConfig.skip_first_search"
            active-text="开启"
            inactive-text="关闭"
            :disabled="!taskConfig.enable_auto_order"
          />
          <span v-else style="color: #606266; line-height: 32px;">
            {{ taskConfig.skip_first_search ? '开启' : '关闭' }}
          </span>
        </el-form-item>
        
        <el-form-item style="margin-left: 16px;">
          <template #label>
            <span style="display: inline-flex; align-items: center; white-space: nowrap;">
              <span>抖动搜索</span>
              <el-tooltip placement="top">
                <template #content>
                  <div style="max-width: 300px; line-height: 1.6;">
                    <strong>抖动搜索（推荐）：</strong>每次搜索间隔会随机增减1-2秒，模拟真人行为，降低被识别风险。<br/>
                    <strong>平均搜索：</strong>严格按照固定时间间隔搜索，适合测试场景。<br/>
                    <span style="color: #67C23A;">💡 建议开启抖动搜索，更安全自然。</span>
                  </div>
                </template>
                <el-icon style="margin-left: 4px; cursor: pointer; color: #909399; font-size: 14px;">
                  <QuestionFilled />
                </el-icon>
              </el-tooltip>
            </span>
          </template>
          <el-switch
            v-if="!isAdmin || !selectedViewUserId"
            v-model="taskConfig.enable_jitter"
            active-text="开启"
            inactive-text="关闭"
          />
          <span v-else style="color: #606266; line-height: 32px;">
            {{ taskConfig.enable_jitter ? '开启' : '关闭' }}
          </span>
        </el-form-item>
        
        <el-form-item label="显示记录数">
          <el-input
            v-if="!isAdmin || !selectedViewUserId"
            v-model="taskConfig.display_count"
            placeholder="显示数量"
            style="width: 120px"
            type="number"
            min="1"
            max="30"
            @change="onDisplayCountChange"
          >
            <template #append>条</template>
          </el-input>
          <span v-else style="color: #606266; padding: 0 11px; line-height: 32px;">
            {{ taskConfig.display_count || '-' }} 条
          </span>
        </el-form-item>
        
        <!-- ✅ 调整：把黑名单按钮移到表单内 -->
        <el-form-item>
          <el-button type="danger" plain icon="User" @click="showSellerBlacklist">
            商家黑名单
          </el-button>
          <el-button type="danger" plain icon="Document" @click="showTitleBlacklist">
            标题黑名单
          </el-button>
        </el-form-item>
        </el-form>
        
        <!-- ✅ 运行中进度条动画（配置区域下方） -->
      </el-collapse-item>
    </el-collapse>

    <!-- 任务状态区（可折叠） -->
    <el-collapse v-model="activeCollapse" class="mb-4">
      <el-collapse-item name="taskStatus">
        <template #title>
          <span style="font-weight: 600;">
            <el-icon style="margin-right: 8px;"><Odometer /></el-icon>
            任务状态
          </span>
          <el-tag :type="taskStatus === 'running' ? 'success' : 'info'" style="margin-left: 12px;">
            {{ taskStatus === 'running' ? '运行中' : '已停止' }}
          </el-tag>
          <!-- ✅ 调整：把"下次搜索"放到title区域，收起面板也能看到 -->
          <span style="margin-left: 24px; color: #606266;">
            <el-icon style="margin-right: 4px;"><Clock /></el-icon>
            下次搜索: <span style="color: #409EFF; font-weight: 600;">{{ nextSearchTime }}</span>
          </span>
        </template>

        <el-row :gutter="20">
          <el-col :span="4">
            <el-statistic title="可用搜索账户" :value="searchAgentCount">
              <template #suffix>台</template>
            </el-statistic>
          </el-col>
          <el-col :span="4">
            <el-statistic title="可用下单账户" :value="orderAgentCount">
              <template #suffix>台</template>
            </el-statistic>
          </el-col>
          <el-col :span="4">
            <el-statistic title="搜索轮数" :value="searchRounds">
              <template #suffix>轮</template>
            </el-statistic>
          </el-col>
          <el-col :span="5">
            <el-statistic title="当前搜索" :value="currentSearchAgent || '-'" />
          </el-col>
        </el-row>
      </el-collapse-item>
    </el-collapse>

    <!-- 搜索结果表 -->
    <el-card>
      <template #header>
        <div class="card-header">
          <span style="font-weight: 600;">
            <el-icon style="margin-right: 8px;"><List /></el-icon>
            搜索结果
            <!-- ✅ 运行中指示器（搜索结果标题旁） -->
            <span v-if="taskStatus === 'running'" class="search-running-badge">
              <el-icon class="search-running-icon"><Loading /></el-icon>
              <span class="search-running-text">搜索中...</span>
            </span>
          </span>
          <div>
            <el-button icon="Document" type="primary" @click="handleRealtimeLog">实时日志</el-button>
            <el-button v-if="!isAdmin || !selectedViewUserId" icon="Refresh" @click="handleRefreshResults">刷新</el-button>
            <el-button icon="Download" @click="handleExport">导出</el-button>
          </div>
        </div>
      </template>
      
      <el-table
        :data="searchResults"
        border
        v-loading="loading"
        style="width: 100%"
        :row-class-name="getRowClassName"
      >
        <el-table-column label="序号" type="index" width="60" align="center" />
        
        <el-table-column label="关键词" width="140" align="center">
          <template #default="{ row }">
            {{ row.keyword || taskConfig.keyword || '-' }}
          </template>
        </el-table-column>
        
        <el-table-column label="商品图片" width="100" align="center">
          <template #default="{ row }">
            <div 
              v-if="row.image_url"
              @click="handleImagePreview(row)"
              style="width: 70px; height: 70px; border-radius: 4px; cursor: pointer; overflow: hidden; position: relative;"
            >
              <el-image
              :src="row.image_url"
              fit="cover"
                style="width: 100%; height: 100%;"
                :preview-src-list="[]"
                :hide-on-click-modal="true"
            />
            </div>
            <span v-else style="color: #C0C4CC;">-</span>
          </template>
        </el-table-column>
        
        <el-table-column label="标题" prop="title" min-width="250" show-overflow-tooltip />
        
        <el-table-column label="标签" prop="tagname" width="100" align="center">
          <template #default="{ row }">
            <el-tag v-if="row.tagname || row.tagName" type="info" size="small">
              {{ row.tagname || row.tagName || '-' }}
            </el-tag>
            <span v-else style="color: #909399;">-</span>
          </template>
        </el-table-column>
        
        <el-table-column label="价格" prop="price" width="100" align="center">
          <template #default="{ row }">
            <span style="color: #F56C6C; font-weight: 600; font-size: 14px;">
              ¥{{ row.price }}
            </span>
          </template>
        </el-table-column>
        
        <el-table-column label="卖家" width="120" align="center">
          <template #default="{ row }">
            <div style="font-weight: 500;">{{ row.seller_nick || '-' }}</div>
          </template>
        </el-table-column>
        
        <el-table-column label="发布时间" prop="publish_time" width="160" align="center">
          <template #default="{ row }">
            {{ formatPublishTime(row.publish_time) }}
          </template>
        </el-table-column>
        
        <el-table-column label="搜索时间" prop="search_time" width="160" align="center" />
        
        <el-table-column label="状态" width="110" align="center">
          <template #default="{ row }">
            <el-tag v-if="row.is_new" type="success" effect="dark">
              新商品
            </el-tag>
            <span v-else style="color: #909399;">-</span>
          </template>
        </el-table-column>
        
        <el-table-column label="下单状态" width="120" align="center">
          <template #default="{ row }">
            <el-tag v-if="row.is_ordered" type="success">已下单</el-tag>
            <el-tag v-else-if="row.order_failed" type="danger">下单失败</el-tag>
            <span v-else style="color: #909399;">未下单</span>
          </template>
        </el-table-column>
        
        <!-- ✅ 管理员查看其他用户时，隐藏操作列 -->
        <el-table-column v-if="!isAdmin || !selectedViewUserId" label="操作" width="220" align="center" fixed="right">
          <template #default="{ row }">
            <el-button
              link
              type="warning"
              icon="FolderDelete"
              @click="handleBlacklistSeller(row)"
            >
              拉黑卖家
            </el-button>
            <el-button
              link
              type="primary"
              icon="ShoppingCart"
              @click="handleManualOrder(row)"
              :disabled="row.is_ordered"
            >
              下单
            </el-button>
            <el-button
              link
              type="info"
              icon="ChatDotRound"
              @click="handleChat(row)"
            >
              对话
            </el-button>
          </template>
        </el-table-column>
      </el-table>

      <!-- 不使用分页，显示固定数量的最新记录 -->
      <div class="mt-4" style="text-align: right; color: #909399; font-size: 12px;">
        显示最新 {{ searchResults.length }} 条记录
      </div>
    </el-card>

    <!-- 图片预览弹窗 -->
    <el-dialog
      v-model="imagePreviewVisible"
      title="商品图片预览"
      width="800px"
      :close-on-click-modal="true"
      append-to-body
    >
      <div style="text-align: center;">
        <el-image
          :src="previewImageUrl"
          fit="contain"
          style="max-width: 100%; max-height: 600px;"
          :preview-src-list="[]"
        />
        <div v-if="previewImageTitle" style="margin-top: 16px; color: #606266; font-size: 14px;">
          {{ previewImageTitle }}
        </div>
      </div>
      <template #footer>
        <el-button @click="imagePreviewVisible = false">关闭</el-button>
      </template>
    </el-dialog>

    <!-- 卖家对话弹窗 -->
    <el-dialog
      v-model="chatDialogVisible"
      title="与卖家对话"
      width="520px"
      :close-on-click-modal="false"
      @close="resetChatForm"
    >
      <el-descriptions :column="1" border size="small" style="margin-bottom: 16px;">
        <el-descriptions-item label="卖家昵称">
          {{ chatForm.sellerName || '-' }}
        </el-descriptions-item>
        <el-descriptions-item label="卖家ID">
          {{ chatForm.sellerId || '-' }}
        </el-descriptions-item>
        <el-descriptions-item label="商品标题">
          {{ chatForm.itemTitle || '-' }}
        </el-descriptions-item>
        <el-descriptions-item label="商品ID">
          {{ chatForm.itemId || '-' }}
        </el-descriptions-item>
        <el-descriptions-item label="商品价格">
          <span v-if="chatForm.price" style="color: #F56C6C; font-weight: 600;">¥{{ chatForm.price }}</span>
          <span v-else>-</span>
        </el-descriptions-item>
      </el-descriptions>

      <el-form label-width="90px">
        <el-form-item label="聊天客户端">
          <el-select
            v-model="selectedChatClient"
            placeholder="请选择用于聊天的客户端"
            style="width: 100%;"
          >
            <el-option
              v-for="client in availableChatClients"
              :key="client.client_id"
              :label="client.client_name || client.hostname || client.client_id"
              :value="client.client_id"
            />
          </el-select>
          <div
            v-if="!availableChatClients.length"
            style="margin-top: 8px; color: #F56C6C; font-size: 12px;"
          >
            暂无在线搜索客户端，请先启动并登录客户端
          </div>
        </el-form-item>
        <el-form-item label="消息内容">
          <el-input
            v-model="chatForm.message"
            type="textarea"
            :rows="4"
            maxlength="500"
            show-word-limit
            placeholder="输入要发送给卖家的消息..."
          />
        </el-form-item>
      </el-form>

      <template #footer>
        <el-button @click="chatDialogVisible = false">取消</el-button>
        <el-button
          type="primary"
          :disabled="!availableChatClients.length"
          :loading="chatSending"
          @click="handleSendChat"
        >
          发送
        </el-button>
      </template>
    </el-dialog>

    <!-- 商家黑名单弹窗 -->
    <SellerBlacklistDialog
      v-model="sellerBlacklistVisible"
      ref="sellerBlacklistRef"
      :readonly="isAdmin && selectedViewUserId"
    />
    
    <!-- 标题黑名单弹窗 -->
    <TitleBlacklistDialog
      v-model="titleBlacklistVisible"
      ref="titleBlacklistRef"
      :readonly="isAdmin && selectedViewUserId"
    />

    <!-- 实时日志弹窗 -->
    <el-dialog
      v-model="logDialogVisible"
      title="搜索任务实时日志"
      width="80%"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      destroy-on-close
    >
      <div class="log-container">
        <div class="log-toolbar">
          <el-input
            v-model="logFilter"
            placeholder="过滤日志（支持客户端ID）"
            style="width: 300px; margin-right: 10px;"
            clearable
          />
          <el-input-number
            v-model="logLines"
            :min="100"
            :max="10000"
            :step="100"
            style="width: 150px; margin-right: 10px;"
          />
          <el-button icon="Refresh" @click="loadLogs">刷新</el-button>
          <el-button
            :icon="autoRefresh ? 'VideoPlay' : 'VideoPause'"
            :type="autoRefresh ? 'success' : 'info'"
            @click="toggleAutoRefresh"
          >
            {{ autoRefresh ? '停止自动刷新' : '自动刷新' }}
          </el-button>
          <el-button icon="Download" @click="downloadLogs">下载</el-button>
        </div>
        <div
          ref="logContentRef"
          class="log-content"
          v-loading="logLoading"
        >
          <pre v-if="logText" class="log-text">{{ logText }}</pre>
          <div v-else class="log-empty">暂无日志</div>
        </div>
      </div>
    </el-dialog>
    
    <!-- ✅ 配置保存提示对话框 -->
    <el-dialog
      v-model="configSaveDialogVisible"
      title="提示"
      width="450px"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
    >
      <div>
        <p style="margin-bottom: 16px;">请保存配置再运行，否则下次打开将显示旧配置</p>
        <el-checkbox v-model="skipSaveWarning">
          下次默认此操作不在提醒
        </el-checkbox>
      </div>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="handleConfigSaveDialog('cancel')">取消</el-button>
          <el-button type="warning" @click="handleConfigSaveDialog('run')">直接运行</el-button>
          <el-button type="primary" @click="handleConfigSaveDialog('save')">保存并运行</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, reactive, computed, onMounted, onUnmounted, onActivated, nextTick } from 'vue'
import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
import {
  Setting,
  Odometer,
  List,
  Refresh,
  Download,
  VideoPlay,
  VideoPause,
  DocumentChecked,
  ShoppingCart,
  FolderDelete,
  User,
  Document as DocumentIcon,
  Clock,
  Loading,
  QuestionFilled
} from '@element-plus/icons-vue'
import SellerBlacklistDialog from './components/SellerBlacklistDialog.vue'
import TitleBlacklistDialog from './components/TitleBlacklistDialog.vue'
import { 
  schedulerStart, 
  schedulerStop, 
  schedulerStatus, 
  getAgentLogs,
  saveCurrentConfig,
  getCurrentConfig,
  manualSearch,
  manualOrder,
  getRecentResults,
  getAgentClientList,
  getUsersWithTasks
} from '@/api/agent'
import { openChat } from '@/api/chat'
import { websocketManager } from '@/utils/websocket'
import { useAgentStore } from '@/store/modules/agent'
import useChatStore from '@/store/modules/chat'
import useUserStore from '@/store/modules/user'

// ==================== 任务配置 ====================
const agentStore = useAgentStore()
const userStore = useUserStore()

// ✅ 管理员切换用户相关
const isAdmin = computed(() => {
  // 判断是否是管理员（role_id=1或permissions包含*:*:*）
  const permissions = userStore.permissions || []
  const roles = userStore.roles || []
  return permissions.includes('*:*:*') || 
         roles.some(role => {
           if (typeof role === 'object') {
             return role.roleId === 1 || role.role_id === 1
           }
           return role === 'admin' || role === 1
         })
})
const usersWithTasks = ref([])
const selectedViewUserId = ref(null)  // 当前查看的用户ID（管理员使用）

const activeCollapse = ref(['taskConfig', 'taskStatus']) // 默认展开两个区域
const STORAGE_KEY = 'search_task_config_v1'
const taskConfig = reactive({
  keyword: '',
  min_price: null,
  max_price: null,
  order_price: 0,
  total_time: 60,
  enable_auto_order: false,
  skip_first_search: false,  // ✅ 首次搜索不自动下单
  enable_jitter: true,  // ✅ 抖动搜索（默认开启，更安全）
  display_count: 30  // 显示的搜索记录数（不影响搜索API参数）
})

// ==================== 任务状态 ====================
const taskStatus = ref('stopped') // stopped / running
const currentTaskId = ref(null)  // ✅ 当前任务ID（从保存配置的响应中获取）
const searchAgentCount = ref(0)
const orderAgentCount = ref(0)
const currentSearchAgent = ref('')
const nextSearchTime = ref('-')
const todaySearchCount = ref(0)
const searchRounds = ref(0)
const lastSearchAt = ref('-')
let statusTimer = null
let adminRefreshTimer = null  // ✅ 管理员模式下的定时刷新器
const STATUS_STORAGE_KEY = 'search_task_status_v1'
const SEARCH_RESULTS_STORAGE_KEY = 'search_task_results_v1'

// ==================== 搜索结果 ====================
const loading = ref(false)
const searchResults = ref([])

// ==================== 对话功能 ====================
const chatDialogVisible = ref(false)
const chatSending = ref(false)
const selectedChatClient = ref('')
const chatForm = reactive({
  sellerName: '',
  sellerId: '',
  itemTitle: '',
  itemId: '',
  price: '',
  keyword: '',
  message: ''
})

// 聊天可用客户端：只使用下单类型的客户端（order类型）
const availableChatClients = computed(() => {
  if (!agentStore?.clients) return []
  return agentStore.clients.filter(c => 
    c.client_type === 'order' &&
    c.online_status === 'online' && 
    c.login_status === 'logged_in'
  )
})


// ==================== 黑名单 ====================
const sellerBlacklistVisible = ref(false)
const titleBlacklistVisible = ref(false)
const sellerBlacklistRef = ref(null)
const titleBlacklistRef = ref(null)

// ==================== Methods ====================

/**
 * 保存任务配置
 */
async function handleSaveConfig() {
  if (!taskConfig.keyword) {
    ElMessage.warning('请输入搜索关键词')
    return
  }
  if (!normalizeAndValidateConfig()) {
    return
  }
  
  try {
    // ✅ 保存到数据库
    // 注意：黑名单是全局的，存储在独立的数据库表中，不需要保存在任务配置中
    const response = await saveCurrentConfig({
      keyword: taskConfig.keyword,
      min_price: Number(taskConfig.min_price) || 0,
      max_price: Number(taskConfig.max_price) || 0,
      order_price: Number(taskConfig.order_price) || 0,
      total_time: Number(taskConfig.total_time) || 60,
      enable_auto_order: !!taskConfig.enable_auto_order,
      skip_first_search: !!taskConfig.skip_first_search,
      enable_jitter: !!taskConfig.enable_jitter,  // ✅ 抖动搜索
      display_count: Number(taskConfig.display_count) || 30
    })
    
    if (response && response.code === 200) {
      // ✅ 保存到 localStorage（作为备份）
      saveConfigToStorage()
      
      // ✅ 如果任务正在运行，直接更新调度器配置使其生效
      if (taskStatus.value === 'running') {
        try {
          // ✅ 获取当前用户ID
          const userId = userStore.id || userStore.user?.userId
          if (!userId) {
            ElMessage.warning('配置已保存，但无法获取用户信息，任务配置未更新')
            return
          }
          
          await schedulerStart({
            keyword: taskConfig.keyword,
            total_time: Number(taskConfig.total_time) || 60,
            enable_auto_order: !!taskConfig.enable_auto_order,
            skip_first_search: !!taskConfig.skip_first_search,
            enable_jitter: !!taskConfig.enable_jitter,  // ✅ 抖动搜索
            order_price: Number(taskConfig.order_price) || 0,
            min_price: Number(taskConfig.min_price) || 0,
            max_price: Number(taskConfig.max_price) || 0,
            display_count: Number(taskConfig.display_count) || 30,
            user_id: userId,  // ✅ 传递用户ID
            task_id: currentTaskId.value  // ✅ 传递任务ID（如果存在）
          })
          ElMessage.success('配置已保存，任务配置已更新并生效')
        } catch (error) {
          ElMessage.warning('配置已保存，但更新任务配置失败：' + error.message)
        }
      } else {
        ElMessage.success('任务配置已保存')
      }
    } else {
      ElMessage.error(response?.msg || '保存配置失败')
    }
  } catch (error) {
    console.error('保存配置失败:', error)
    ElMessage.error('保存失败：' + (error.message || '未知错误'))
  }
}

/**
 * 检查配置是否已保存
 */
function isConfigSaved() {
  try {
    const savedData = localStorage.getItem(STORAGE_KEY)
    if (!savedData) return false
    
    const saved = JSON.parse(savedData)
    const current = {
      keyword: taskConfig.keyword,
      min_price: taskConfig.min_price,
      max_price: taskConfig.max_price,
      order_price: taskConfig.order_price,
      total_time: taskConfig.total_time,
      enable_auto_order: taskConfig.enable_auto_order,
      skip_first_search: taskConfig.skip_first_search,
      enable_jitter: taskConfig.enable_jitter,  // ✅ 抖动搜索
      display_count: taskConfig.display_count
    }
    
    // 深度比较配置是否相同
    return JSON.stringify(saved) === JSON.stringify(current)
  } catch {
    return false
  }
}

// ✅ 配置保存提示对话框
const configSaveDialogVisible = ref(false)
const skipSaveWarning = ref(false)

/**
 * 执行启动任务（实际启动逻辑）
 */
async function doStartTask() {
  try {
    // ✅ 获取当前用户ID
    const userId = userStore.id || userStore.user?.userId
    if (!userId) {
      ElMessage.error('无法获取用户信息，请重新登录')
      return
    }
    
    await schedulerStart({
      keyword: taskConfig.keyword,
      total_time: Number(taskConfig.total_time) || 60,
      enable_auto_order: !!taskConfig.enable_auto_order,
      skip_first_search: !!taskConfig.skip_first_search,
      enable_jitter: !!taskConfig.enable_jitter,  // ✅ 抖动搜索
      order_price: Number(taskConfig.order_price) || 0,
      min_price: Number(taskConfig.min_price) || 0,
      max_price: Number(taskConfig.max_price) || 0,
      display_count: Number(taskConfig.display_count) || 30,
      user_id: userId,  // ✅ 传递用户ID（用于多用户隔离）
      task_id: currentTaskId.value  // ✅ 传递任务ID（如果存在）
    })
    taskStatus.value = 'running'
    ElMessage.success('搜索任务已启动')
    startStatusPolling()
    saveStatusToStorage()  // 保存状态
  } catch (error) {
    ElMessage.error('启动失败：' + error.message)
  }
}

/**
 * 启动任务
 */
async function handleStartTask() {
  if (!taskConfig.keyword) {
    ElMessage.warning('请先配置搜索关键词')
    return
  }
  if (!normalizeAndValidateConfig()) {
    return
  }
  
  // ✅ 检查配置是否已保存
  const configSaved = isConfigSaved()
  
  if (!configSaved) {
    // 检查是否勾选了"下次不再提醒"
    const skipWarning = localStorage.getItem('search_task_skip_save_warning') === 'true'
    
    if (skipWarning) {
      // 已勾选"下次不再提醒"，直接启动（不保存配置）
      await doStartTask()
      return
    }
    
    // 未勾选，显示自定义对话框
    configSaveDialogVisible.value = true
    skipSaveWarning.value = false
    return
  } else {
    // 配置已保存，直接启动
    saveConfigToStorage()  // 更新保存时间
    await doStartTask()
  }
}

/**
 * 处理配置保存对话框的确认
 */
function handleConfigSaveDialog(action) {
  configSaveDialogVisible.value = false
  
  // 如果勾选了"下次不再提醒"
  if (skipSaveWarning.value) {
    localStorage.setItem('search_task_skip_save_warning', 'true')
  }
  
  if (action === 'save') {
    // 保存并运行
    saveConfigToStorage()
    doStartTask()
  } else if (action === 'run') {
    // 直接运行（不保存）
    doStartTask()
  }
  // action === 'cancel' 时直接关闭对话框，不执行任何操作
}

/**
 * 停止任务
 */
async function handleStopTask() {
  try {
    await ElMessageBox.confirm(
      '确定要停止搜索任务吗？',
      '提示',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }
    )
    
    // ✅ 获取当前用户ID并停止对应调度器
    const userId = userStore.id || userStore.user?.userId
    if (userId) {
      await schedulerStop({ user_id: userId })  // ✅ 传递用户ID
    } else {
      await schedulerStop()  // 兼容旧代码
    }
    taskStatus.value = 'stopped'
    currentSearchAgent.value = ''
    nextSearchTime.value = '-'
    // 不清除搜索轮数和今日搜索次数（保留统计）
    ElMessage.success('搜索任务已停止')
    stopStatusPolling()
    saveStatusToStorage()
  } catch {
    // 取消操作
  }
}

/**
 * 刷新搜索结果
 * 触发受控端执行一次手动搜索
 */
async function handleRefreshResults() {
  if (!taskConfig.keyword) {
    ElMessage.warning('请先配置搜索关键词')
    return
  }
  
  loading.value = true
  try {
    // ✅ 触发一次手动搜索（让受控端执行搜索）
    const response = await manualSearch({
      keyword: taskConfig.keyword,
      min_price: Number(taskConfig.min_price) || 0,
      max_price: Number(taskConfig.max_price) || 0,
      order_price: Number(taskConfig.order_price) || 0,
      total_time: Number(taskConfig.total_time) || 60,
      enable_auto_order: !!taskConfig.enable_auto_order,
      display_count: Number(taskConfig.display_count) || 30
    })
    
    if (response && response.code === 200) {
      ElMessage.success('已发送搜索命令，请等待搜索结果（通过WebSocket实时推送）')
    } else {
      ElMessage.warning(response?.msg || '发送搜索命令失败')
    }
    loading.value = false
  } catch (error) {
    console.error('刷新搜索失败:', error)
    ElMessage.error('发送搜索命令失败：' + (error.message || '未知错误'))
    loading.value = false
  }
}

/**
 * 显示商家黑名单
 */
function showSellerBlacklist() {
  sellerBlacklistVisible.value = true
}

/**
 * 显示标题黑名单
 */
function showTitleBlacklist() {
  titleBlacklistVisible.value = true
}

/**
 * 导出数据
 */
function handleExport() {
  ElMessage.info('导出功能开发中...')
}

/**
 * 拉黑卖家
 */
async function handleBlacklistSeller(row) {
  try {
    const sellerId = row.seller_id || row.sellerId || ''
    const sellerNick = row.seller_nick || row.sellerNick || ''
    
    if (!sellerId && !sellerNick) {
      ElMessage.warning('该商品缺少卖家信息，无法拉黑')
      return
    }
    
    await ElMessageBox.confirm(
      `确定要拉黑卖家 "${sellerNick || sellerId}" 吗？\n卖家ID: ${sellerId || '-'}`,
      '拉黑卖家',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }
    )
    
    // ✅ 调用API拉黑卖家（优先使用seller_id进行精准过滤）
    const { addSellerBlacklist } = await import('@/api/blacklist')
    const response = await addSellerBlacklist({
      seller_id: sellerId,  // ✅ 优先使用seller_id进行精准过滤
      seller_nick: sellerNick,
      reason: '从搜索结果拉黑'
    })
    
    if (response.code === 200) {
      ElMessage.success('卖家已拉黑，后续搜索结果将自动过滤该卖家')
      // ✅ 刷新黑名单弹窗（如果已打开）
      if (sellerBlacklistRef.value && typeof sellerBlacklistRef.value.refresh === 'function') {
        sellerBlacklistRef.value.refresh()
      } else {
        // 如果弹窗未打开，尝试打开并刷新
        console.log('商家黑名单弹窗未打开，无法自动刷新')
      }
    } else {
      ElMessage.error(response.msg || '拉黑失败')
    }
  } catch (error) {
    if (error !== 'cancel') {
      console.error('拉黑卖家失败:', error)
      ElMessage.error('拉黑失败：' + (error.message || '未知错误'))
    }
  }
}

/**
 * 手动下单
 */
async function handleManualOrder(row) {
  try {
    await ElMessageBox.confirm(
      `确定要下单商品 "${row.title}" 吗？\n价格：¥${row.price}`,
      '手动下单',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }
    )
    
    // ✅ 调用真实的下单API
    const response = await manualOrder({
      item_id: row.item_id || row.itemId || row.id,
      title: row.title,
      price: row.price,
      keyword: row.keyword || taskConfig.keyword || ''
    }, {
      allow_search_accounts: false  // ✅ 手动下单必须使用下单账号，不允许使用搜索账号
    })
    
    if (response.code === 200) {
      ElNotification({
        title: '下单命令已发送',
        message: response.msg || '请等待处理结果（结果将通过WebSocket推送）',
        type: 'success',
        duration: 5000
      })
      
      // 播放声音提示
      playSound()
      
      // 更新本地状态（标记为已下单）
      const itemId = row.item_id || row.itemId || row.id
      const item = searchResults.value.find(r => (r.item_id || r.itemId || r.id) === itemId)
      if (item) {
        item.is_ordered = true
        item.order_status = 'pending'
      }
    } else {
      ElNotification({
        title: '下单失败',
        message: response.msg || '未知错误',
        type: 'error',
        duration: 5000
      })
    }
  } catch (error) {
    if (error !== 'cancel') {
      console.error('手动下单失败:', error)
      ElNotification({
        title: '下单失败',
        message: error.message || '未知错误',
        type: 'error',
        duration: 5000
      })
    }
  }
}

/**
 * 打开全局聊天面板并定位到指定会话
 */
async function handleChat(row) {
  let sellerId = row.seller_id || row.sellerId || row.sellerIdStr || ''
  let sellerName = row.seller_nick || row.sellerName || row.seller || '未知卖家'
  const itemId = row.item_id || row.itemId || row.id || ''
  const itemTitle = row.title || row.item_title || row.itemTitle || ''

  if (!sellerId) {
    ElMessage.warning('缺少卖家信息，无法打开对话')
    return
  }

  // 检查是否有在线的下单客户端
  if (!availableChatClients.value.length) {
    ElMessage.warning('暂无在线的下单客户端，请先启动并登录下单类型的Agent客户端')
    return
  }

  // 使用全局聊天 Store
  const chatStore = useChatStore()
  
  console.log('[SearchTask] 打开对话:', { sellerId, sellerName, itemId, itemTitle })
  
  // 选择客户端（如果未选择，则使用第一个在线客户端）
  if (!chatStore.selectedClientId) {
    chatStore.selectClient(availableChatClients.value[0].client_id)
    console.log('[SearchTask] 已选择客户端:', availableChatClients.value[0].client_id)
  }

  // 构建会话ID
  const sessionId = `${sellerId}#${itemId || ''}`
  
  // ✅ 先调用后端API创建会话记录并获取商品信息（后端使用匿名请求，避免Agent风控）
  let itemInfo = null
  let pureSellerId = sellerId // 默认使用传入的sellerId
  
  if (chatStore.selectedClientId) {
    try {
      const response = await openChat({
        client_id: chatStore.selectedClientId,
        seller_id: sellerId,
        item_id: itemId,
        seller_name: sellerName
      })
      
      console.log('[SearchTask] openChat响应:', response)
      
      // ✅ 后端通过匿名请求获取了商品信息，直接使用
      if (response.code === 200 && response.data) {
        itemInfo = response.data
        
        // ✅ 使用后端返回的纯数字seller_id（从匿名请求获取的）
        if (itemInfo.seller_id) {
          pureSellerId = String(itemInfo.seller_id)
          sellerId = pureSellerId
        } else {
          // 如果后端没有返回seller_id，说明可能获取失败，使用原始ID（但不会发送给Agent）
          console.warn('[SearchTask] 后端未返回seller_id，将跳过发送chat_open命令')
        }
        
        // 更新seller_name（如果后端返回了）
        if (itemInfo.seller_name) {
          sellerName = itemInfo.seller_name
        }
        
        console.log('[SearchTask] 已从后端获取商品信息:', {
          seller_id: pureSellerId,
          seller_name: itemInfo.seller_name,
          item_title: itemInfo.item_title,
          item_price: itemInfo.item_price,
          item_image: itemInfo.item_image,
          item_tags: itemInfo.item_tags,
          seller_avatar: itemInfo.seller_avatar
        })
      }
    } catch (e) {
      console.error('[SearchTask] 调用openChat API失败:', e)
      // 不阻止继续，但会使用默认信息
    }
  }
  
  // ✅ 发送chat_open命令给Agent（仅用于IM连接，不再查询商品信息）
  // ⚠️ 重要：只有成功获取纯数字seller_id后才发送，避免发送加密的seller_id
  // ✅ 必须确保openChat API成功返回了纯数字seller_id
  if (chatStore.selectedClientId && itemInfo && itemInfo.seller_id) {
    // 使用后端返回的纯数字seller_id（确保是纯数字）
    const finalSellerId = String(itemInfo.seller_id)
    const isNumeric = /^\d+$/.test(finalSellerId)
    
    if (isNumeric) {
      try {
        console.log('[SearchTask] 发送chat_open命令给Agent（仅用于IM连接）...', {
          seller_id: finalSellerId,
          item_id: itemId,
          seller_name: itemInfo.seller_name || sellerName
        })
        websocketManager.sendCommand(chatStore.selectedClientId, 'chat_open', {
          seller_id: finalSellerId, // 使用纯数字seller_id
          item_id: itemId,
          seller_name: itemInfo.seller_name || sellerName
        })
      } catch (e) {
        console.error('[SearchTask] 发送chat_open命令失败:', e)
      }
    } else {
      console.warn('[SearchTask] 跳过发送chat_open命令：后端返回的seller_id不是纯数字:', finalSellerId)
    }
  } else {
    console.warn('[SearchTask] 跳过发送chat_open命令：未从后端获取到有效的商品信息或seller_id', {
      hasClientId: !!chatStore.selectedClientId,
      hasItemInfo: !!itemInfo,
      sellerId: itemInfo?.seller_id
    })
  }
  
  // ✅ 添加或更新会话（使用后端返回的商品信息）
  // ⚠️ 如果itemInfo存在，使用itemInfo.seller_id（纯数字），否则使用pureSellerId
  const finalSellerIdForSession = itemInfo?.seller_id ? String(itemInfo.seller_id) : pureSellerId
  chatStore.addOrUpdateSession({
    sellerId: finalSellerIdForSession, // 使用纯数字seller_id
    sellerName: itemInfo?.seller_name || sellerName,
    itemId: itemId,
    itemTitle: itemInfo?.item_title || itemTitle || row.title || row.item_title || null,
    itemPrice: itemInfo?.item_price || row.price || row.item_price || null,
    itemImage: itemInfo?.item_image || row.item_image || row.itemImage || row.main_pic || null,
    itemTags: itemInfo?.item_tags || row.tags || row.item_tags || [], // 使用后端返回的标签
    avatar: itemInfo?.seller_avatar || row.seller_avatar || row.sellerAvatar || row.seller_portrait || null,
    lastMessage: '点击查看会话',
    lastTime: new Date().toISOString()
  })
  
  console.log('[SearchTask] 已更新会话信息:', {
    sellerId: pureSellerId,
    sellerName: itemInfo?.seller_name || sellerName,
    itemTitle: itemInfo?.item_title,
    itemPrice: itemInfo?.item_price,
    itemImage: itemInfo?.item_image,
    itemTags: itemInfo?.item_tags,
    avatar: itemInfo?.seller_avatar
  })
  
  // ✅ 更新会话ID（因为seller_id可能已更新为纯数字ID）
  const updatedSessionId = `${finalSellerIdForSession}#${itemId || ''}`

  // 设置当前会话
  console.log('[SearchTask] 构建的 sessionId:', updatedSessionId, 'seller_id:', finalSellerIdForSession)
  console.log('[SearchTask] 当前会话列表:', chatStore.sessions)
  
  chatStore.setCurrentSession(updatedSessionId)

  // 打开聊天面板
  chatStore.setVisible(true)
  
  // ✅ 等待一小段时间让会话创建完成，然后触发会话选择
  // 这样ChatPanel会自动加载消息并选中会话
  await new Promise(resolve => setTimeout(resolve, 500))
  
  // ✅ 触发会话刷新（确保会话列表是最新的）
  // ChatPanel会监听到currentSessionId变化并自动加载消息
  console.log('[SearchTask] 等待会话创建完成，当前会话ID:', chatStore.currentSessionId)

  ElMessage.success(`已打开与 ${sellerName} 的对话`)
}

/**
 * 发送聊天消息（占位实现）
 */
async function handleSendChat() {
  if (!selectedChatClient.value) {
    ElMessage.warning('请选择用于聊天的客户端')
    return
  }
  if (!chatForm.message || !chatForm.message.trim()) {
    ElMessage.warning('请输入要发送的消息内容')
    return
  }

  chatSending.value = true
  try {
    // TODO: 接入后端API，通过指定客户端发送消息给卖家
    await new Promise(resolve => setTimeout(resolve, 400))
    ElMessage.success('消息已暂存，聊天功能接入后将支持发送')
    chatDialogVisible.value = false
  } catch (error) {
    console.error('发送聊天消息失败:', error)
    ElMessage.error(error.message || '发送失败，请稍后再试')
  } finally {
    chatSending.value = false
  }
}

/**
 * 重置聊天表单
 */
function resetChatForm() {
  chatForm.sellerName = ''
  chatForm.sellerId = ''
  chatForm.itemTitle = ''
  chatForm.itemId = ''
  chatForm.price = ''
  chatForm.keyword = ''
  chatForm.message = ''
  selectedChatClient.value = ''
}

/**
 * 播放声音提示
 */
function playSound() {
  // TODO: 播放提示音
  console.log('播放提示音')
}

/**
 * 更新任务状态
 * 
 * API响应格式统一：
 * - 后端返回：{ code: 200, msg: "success", data: { running: boolean, ... } }
 * - 拦截器处理：code === 200 时返回 res.data，即 { code: 200, msg: "success", data: {...} }
 * - 因此 res 固定格式：{ code: 200, data: { running: ..., ... } }
 */
async function updateTaskStatus() {
  try {
    // ✅ 获取当前用户ID并传递给后端
    // 如果是管理员查看其他用户，使用selectedViewUserId
    const userId = (isAdmin.value && selectedViewUserId.value) 
      ? selectedViewUserId.value 
      : (userStore.id || userStore.user?.userId)
    const params = userId ? { user_id: userId } : {}
    // ✅ 如果是管理员查看其他用户，传递filter_user_id
    if (isAdmin.value && selectedViewUserId.value) {
      params.filter_user_id = selectedViewUserId.value
    }
    const res = await schedulerStatus(params)
    
    // 统一格式：确保从 res.data 获取实际数据
    const data = res?.data || {}
    const isRunning = Boolean(data.running)
    const newStatus = isRunning ? 'running' : 'stopped'
    
    // 更新任务状态
    if (taskStatus.value !== newStatus) {
      taskStatus.value = newStatus
      console.log('[SearchTask] 任务状态变化:', { from: taskStatus.value, to: newStatus })
    }
    
    // 更新统计信息
    searchAgentCount.value = data.search_client_count ?? 0
    orderAgentCount.value = data.order_client_count ?? 0
    // ✅ 将 client_id 映射为客户端名称或显示ID（如果无法映射）
    const clientId = data.current_client_id || ''
    if (isRunning && clientId) {
      // 尝试从 agent store 获取客户端名称
      try {
        const agentStore = useAgentStore()
        const client = agentStore.clients?.find(c => c.client_id === clientId)
        currentSearchAgent.value = client?.client_name || client?.hostname || clientId
        console.log('[SearchTask] 当前搜索客户端:', { clientId, clientName: currentSearchAgent.value })
      } catch (e) {
        // 如果无法获取，直接显示ID
        currentSearchAgent.value = clientId
        console.warn('[SearchTask] 无法从store获取客户端信息:', e)
      }
    } else {
      // 任务未运行或没有当前客户端，清空显示
      currentSearchAgent.value = ''
    }
    nextSearchTime.value = data.next_search_time || '-'
    
    // ✅ 更新搜索轮数（从后端获取，如果后端提供了）
    // 注意：后端轮数 = 所有客户端都搜索完一次算一轮
    // 前端轮数 = 每收到一次搜索结果算一轮（可能不准确，因为可能漏掉某些搜索结果）
    // 优先使用后端轮数（更准确）
    if (data.round_count !== undefined && data.round_count !== null && data.round_count > 0) {
      // 后端提供了轮数，使用后端的值（更准确，因为后端知道所有客户端的搜索情况）
      searchRounds.value = data.round_count
      console.log('[SearchTask] 从后端更新搜索轮数:', data.round_count)
    }
    // 注意：如果后端没有提供round_count或为0，前端会在收到搜索结果时自己增加（见handleWebSocketMessage）
    
    // 同步轮询状态
    if (isRunning && !statusTimer) {
      startStatusPolling()
    } else if (!isRunning && statusTimer) {
      stopStatusPolling()
    }
    
    // 保存状态到localStorage
    saveStatusToStorage()
  } catch (error) {
    console.error('[SearchTask] 更新任务状态失败:', error)
  }
}

function startStatusPolling() {
  stopStatusPolling()
  statusTimer = setInterval(updateTaskStatus, 5000)
}

function stopStatusPolling() {
  if (statusTimer) {
    clearInterval(statusTimer)
    statusTimer = null
  }
}

/**
 * ✅ 管理员模式：启动定时刷新（任务状态和搜索结果）
 */
function startAdminRefresh() {
  stopAdminRefresh()
  if (!isAdmin.value || !selectedViewUserId.value) {
    return
  }
  
  // 每5秒刷新一次任务状态和搜索结果
  adminRefreshTimer = setInterval(async () => {
    if (isAdmin.value && selectedViewUserId.value) {
      // console.log('[SearchTask] 管理员模式：定时刷新任务状态和搜索结果')  // 高频日志，已注释
      await updateTaskStatus()
      // ✅ 定时刷新时强制刷新搜索结果
      await loadSearchResultsFromStorage(true)
    } else {
      // 如果不是管理员模式了，停止刷新
      stopAdminRefresh()
    }
  }, 5000)
  
  // console.log('[SearchTask] 管理员模式：已启动定时刷新（每5秒）')  // 高频日志，已注释
}

/**
 * ✅ 管理员模式：停止定时刷新
 */
function stopAdminRefresh() {
  if (adminRefreshTimer) {
    clearInterval(adminRefreshTimer)
    adminRefreshTimer = null
    // console.log('[SearchTask] 管理员模式：已停止定时刷新')  // 高频日志，已注释
  }
}

// ==================== 校验与联动 ====================
function toNumberOrZero(value) {
  const n = Number(value)
  return isNaN(n) ? 0 : n
}

function onMinPriceChange() {
  // 允许 0 或空 表示不限制
  if (taskConfig.min_price === '' || taskConfig.min_price === null) return
  const min = Math.max(0, toNumberOrZero(taskConfig.min_price))
  taskConfig.min_price = min
  // 上限小于下限时，自动同步到下限
  if (toNumberOrZero(taskConfig.max_price) > 0 && toNumberOrZero(taskConfig.max_price) < min) {
    taskConfig.max_price = min
  }
  // 下单价在设置了下限时不可低于下限（否则永远无法下单）
  if (toNumberOrZero(taskConfig.order_price) > 0 && toNumberOrZero(taskConfig.order_price) < min) {
    taskConfig.order_price = min
    ElMessage.info('已将下单价格调整为不低于最低价')
  }
}

function onMaxPriceChange() {
  if (taskConfig.max_price === '' || taskConfig.max_price === null) return
  const max = Math.max(0, toNumberOrZero(taskConfig.max_price))
  taskConfig.max_price = max
  // 上限小于下限时，提升下限到上限
  if (toNumberOrZero(taskConfig.min_price) > 0 && toNumberOrZero(taskConfig.min_price) > max && max > 0) {
    taskConfig.min_price = max
    ElMessage.info('最低价已调整为不高于最高价')
  }
}

function onOrderPriceChange() {
  const orderPrice = Math.max(0, toNumberOrZero(taskConfig.order_price))
  taskConfig.order_price = orderPrice
  const min = toNumberOrZero(taskConfig.min_price)
  // 订单价格为 0 表示所有新商品都下单
  if (orderPrice === 0) return
  if (min > 0 && orderPrice < min) {
    taskConfig.order_price = min
    ElMessage.warning('下单价格不能低于最低价，否则会永远无法下单')
  }
}

function onDisplayCountChange() {
  let n = toNumberOrZero(taskConfig.display_count)
  if (n < 1) n = 1
  if (n > 30) n = 30
  taskConfig.display_count = n
}

/**
 * 处理图片预览（使用自定义对话框，避免Element Plus预览的混乱显示）
 */
const imagePreviewVisible = ref(false)
const previewImageUrl = ref('')
const previewImageTitle = ref('')

function handleImagePreview(row) {
  if (row.image_url) {
    previewImageUrl.value = row.image_url
    previewImageTitle.value = row.title || '商品图片预览'
    imagePreviewVisible.value = true
  }
}

// ==================== 管理员切换用户功能 ====================
/**
 * 加载有任务的用户列表（仅管理员）
 */
async function loadUsersWithTasks() {
  if (!isAdmin.value) return
  
  try {
    const res = await getUsersWithTasks()
    if (res.code === 200 && res.data) {
      usersWithTasks.value = res.data
      
      // 默认选择第一个用户
      if (res.data.length > 0 && !selectedViewUserId.value) {
        selectedViewUserId.value = res.data[0].user_id
        await handleUserSwitch(res.data[0].user_id)
      }
    }
  } catch (error) {
    console.error('[SearchTask] 加载用户列表失败:', error)
  }
}

/**
 * 获取当前查看的用户名
 */
function getCurrentViewUserName() {
  if (!selectedViewUserId.value) return ''
  const user = usersWithTasks.value.find(u => u.user_id === selectedViewUserId.value)
  return user ? (user.nick_name || user.user_name) : ''
}

/**
 * 切换用户（管理员功能）
 */
async function handleUserSwitch(userId) {
  if (!userId) {
    // 清空选择，恢复查看自己的数据
    selectedViewUserId.value = null
    // 停止管理员模式的定时刷新
    stopAdminRefresh()
    // 重新加载自己的配置
    await loadUserConfig()
    return
  }
  
  selectedViewUserId.value = userId
  
  // 重新加载该用户的配置和搜索结果
  await loadUserConfig(userId)
  // ✅ 切换用户时强制刷新搜索结果
  await loadSearchResultsFromStorage(true)
  
  // ✅ 启动管理员模式的定时刷新
  startAdminRefresh()
}

/**
 * 加载用户配置（支持管理员查看其他用户）
 * @returns {Promise<boolean>} 是否成功加载配置
 */
async function loadUserConfig(viewUserId = null) {
  try {
    // ✅ 如果是管理员查看其他用户，传递filter_user_id参数
    const params = {}
    if (isAdmin.value && viewUserId) {
      params.filter_user_id = viewUserId
    }
    
    const response = await getCurrentConfig(params)
    if (response && response.code === 200 && response.data) {
      const config = response.data
      // 更新任务配置
      Object.keys(taskConfig).forEach(key => {
        if (config.hasOwnProperty(key)) {
          taskConfig[key] = config[key]
        }
      })
      return true  // ✅ 成功加载配置
    } else {
      console.log('[SearchTask] 数据库中无保存的配置')
      return false  // ✅ 数据库中没有配置
    }
  } catch (error) {
    console.error('[SearchTask] 加载用户配置失败:', error)
    throw error  // ✅ 抛出错误，让外层处理
  }
}

/**
 * 加载配置（带降级方案）
 * @param {number|null} targetUserId - 目标用户ID（管理员查看其他用户时使用）
 */
async function loadConfigWithFallback(targetUserId) {
  try {
    const loadedFromDb = await loadUserConfig(targetUserId)
    if (loadedFromDb) {
      console.log(`[SearchTask] ✅ 已从数据库加载任务配置${targetUserId ? `（用户ID: ${targetUserId}）` : ''}`)
    } else {
      // ⚠️ 管理员查看其他用户时，如果数据库中没有配置，不使用localStorage（避免加载管理员自己的配置）
      if (targetUserId) {
        console.log(`[SearchTask] 数据库中无用户配置（用户ID: ${targetUserId}），保持空配置`)
      } else {
        console.log('[SearchTask] 数据库中无配置，尝试从localStorage恢复')
        loadConfigFromStorage()
      }
    }
  } catch (error) {
    console.warn('[SearchTask] ⚠️ 从数据库加载配置失败:', error)
    // ⚠️ 管理员查看其他用户时出错，不使用localStorage降级
    if (!targetUserId) {
      console.log('[SearchTask] 尝试从localStorage恢复')
      loadConfigFromStorage()
    }
  }
}

function normalizeAndValidateConfig() {
  // 统一数值
  onDisplayCountChange()
  if (taskConfig.min_price !== null && taskConfig.min_price !== '') onMinPriceChange()
  if (taskConfig.max_price !== null && taskConfig.max_price !== '') onMaxPriceChange()
  onOrderPriceChange()

  // 校验逻辑
  const min = toNumberOrZero(taskConfig.min_price)
  const max = toNumberOrZero(taskConfig.max_price)
  const orderPrice = toNumberOrZero(taskConfig.order_price)

  if (max > 0 && min > 0 && max < min) {
    ElMessage.error('最高价不能低于最低价')
    return false
  }
  if (orderPrice > 0 && min > 0 && orderPrice < min) {
    ElMessage.error('下单价格不能低于最低价')
    return false
  }
  return true
}

// ==================== 本地持久化 ====================
function saveConfigToStorage() {
  try {
    const data = JSON.stringify(taskConfig)
    localStorage.setItem(STORAGE_KEY, data)
  } catch {}
}

function loadConfigFromStorage() {
  try {
    const data = localStorage.getItem(STORAGE_KEY)
    if (!data) return
    const parsed = JSON.parse(data)
    Object.keys(taskConfig).forEach((k) => {
      if (Object.prototype.hasOwnProperty.call(parsed, k)) {
        taskConfig[k] = parsed[k]
      }
    })
  } catch {}
}

/**
 * 保存任务状态到localStorage（搜索轮数、今日搜索次数等）
 */
function saveStatusToStorage() {
  try {
    const statusData = {
      searchRounds: searchRounds.value,
      todaySearchCount: todaySearchCount.value,
      lastSearchAt: lastSearchAt.value,
      taskStatus: taskStatus.value,
      timestamp: new Date().toISOString()
    }
    localStorage.setItem(STATUS_STORAGE_KEY, JSON.stringify(statusData))
  } catch {}
}

/**
 * 从localStorage加载任务状态
 */
function loadStatusFromStorage() {
  try {
    const data = localStorage.getItem(STATUS_STORAGE_KEY)
    if (!data) return
    
    const parsed = JSON.parse(data)
    
    // 检查是否是今天的数据
    const savedDate = parsed.timestamp ? new Date(parsed.timestamp).toDateString() : null
    const today = new Date().toDateString()
    
    if (savedDate === today) {
      // 是同一天的数据，恢复状态
      searchRounds.value = parsed.searchRounds || 0
      todaySearchCount.value = parsed.todaySearchCount || 0
      lastSearchAt.value = parsed.lastSearchAt || '-'
    } else {
      // 不是今天的数据，重置今日统计
      todaySearchCount.value = 0
      lastSearchAt.value = '-'
      // 保留搜索轮数（累计值）
      searchRounds.value = parsed.searchRounds || 0
    }
  } catch {}
}

/**
 * 保存搜索结果到 localStorage
 */
function saveSearchResultsToStorage() {
  try {
    const resultsToSave = searchResults.value.map(item => ({
      ...item,
      // 保存原始数据，但标记 is_new_highlight 会重置
      is_new_highlight: item.is_new_highlight || false
    }))
    
    const data = {
      results: resultsToSave,
      timestamp: new Date().toISOString()
    }
    localStorage.setItem(SEARCH_RESULTS_STORAGE_KEY, JSON.stringify(data))
  } catch (error) {
    console.error('[SearchTask] 保存搜索结果失败:', error)
  }
}

/**
 * 从数据库加载最新搜索结果（作为初始显示，仅在首次加载时使用）
 * ⚠️ 只在 searchResults.value 为空时才加载，避免覆盖已显示的最新数据
 * ✅ 管理员模式下，切换用户时会强制刷新
 */
async function loadSearchResultsFromStorage(forceRefresh = false) {
  // ✅ 如果已经有数据显示且不是强制刷新，不覆盖（保留最新数据）
  if (!forceRefresh && searchResults.value && searchResults.value.length > 0) {
    // console.log(`[SearchTask] 已有 ${searchResults.value.length} 条搜索结果，跳过数据库加载（避免覆盖最新数据）`)  // 高频日志，已注释
    return
  }
  
  try {
    // ✅ 从数据库加载最新搜索结果（仅在首次加载时或强制刷新时）
    const keyword = taskConfig.keyword || null
    // ✅ 如果是管理员查看其他用户，传递filter_user_id
    const params = { keyword, limit: Number(taskConfig.display_count) || 30 }
    if (isAdmin.value && selectedViewUserId.value) {
      params.filter_user_id = selectedViewUserId.value
    }
    const response = await getRecentResults(params)
    
    if (response && response.code === 200 && response.data && response.data.results) {
      const cachedResults = response.data.results || []
      
      // ✅ 恢复搜索结果（去掉高亮标记，因为这是历史缓存数据）
      if (Array.isArray(cachedResults) && cachedResults.length > 0) {
        searchResults.value = cachedResults.map(item => ({
          ...item,
          is_new_highlight: false,  // 历史缓存数据不显示高亮
          is_new: false  // 缓存数据不是新商品
        }))
        // console.log(`[SearchTask] 从数据库加载了 ${searchResults.value.length} 条搜索结果（首次加载）`)  // 高频日志，已注释
      }
    }
  } catch (error) {
    console.error('[SearchTask] 加载搜索结果缓存失败:', error)
    // 如果数据库加载失败，尝试从 localStorage 加载（向后兼容）
    try {
      const data = localStorage.getItem(SEARCH_RESULTS_STORAGE_KEY)
      if (!data) return
      
      const parsed = JSON.parse(data)
      
      // ✅ 只在没有数据时才从localStorage恢复
      if (Array.isArray(parsed.results) && (!searchResults.value || searchResults.value.length === 0)) {
        searchResults.value = parsed.results.map(item => ({
          ...item,
          is_new_highlight: false,
          is_new: false
        }))
        console.log(`[SearchTask] 从 localStorage 恢复了 ${searchResults.value.length} 条搜索结果缓存`)
      }
    } catch (storageError) {
      console.error('[SearchTask] 从 localStorage 加载缓存失败:', storageError)
    }
  }
}

/**
 * 格式化发布时间（Unix时间戳 -> 可读日期）
 */
function formatPublishTime(publishTime) {
  if (!publishTime) return '-'
  
  // 如果是字符串，尝试解析
  if (typeof publishTime === 'string') {
    // 尝试作为ISO字符串解析
    const date = new Date(publishTime)
    if (!isNaN(date.getTime())) {
      return formatDateTime(date)
    }
    return publishTime  // 如果无法解析，直接返回原字符串
  }
  
  // 如果是数字（Unix时间戳），转换
  if (typeof publishTime === 'number') {
    // 判断是秒级还是毫秒级时间戳
    const timestamp = publishTime > 1000000000000 ? publishTime : publishTime * 1000
    const date = new Date(timestamp)
    if (isNaN(date.getTime())) {
      return '-'
    }
    return formatDateTime(date)
  }
  
  return '-'
}

/**
 * 格式化日期时间
 */
function formatDateTime(date) {
  const year = date.getFullYear()
  const month = String(date.getMonth() + 1).padStart(2, '0')
  const day = String(date.getDate()).padStart(2, '0')
  const hours = String(date.getHours()).padStart(2, '0')
  const minutes = String(date.getMinutes()).padStart(2, '0')
  const seconds = String(date.getSeconds()).padStart(2, '0')
  
  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
}

/**
 * 获取表格行的类名（用于新商品背景色高亮和已下单商品特殊背景色）
 */
function getRowClassName({ row, rowIndex }) {
  if (row.is_ordered) {
    return 'row-ordered-item'  // ✅ 已下单商品特殊背景色
  }
  if (row.is_new_highlight) {
    return 'row-new-item'  // 新商品背景色高亮
  }
  return ''
}

// ==================== Lifecycle ====================
onMounted(async () => {
  // ✅ 如果是管理员，加载有任务的用户列表
  if (isAdmin.value) {
    await loadUsersWithTasks()
    // ⚠️ loadUsersWithTasks() 会自动调用 handleUserSwitch()，已经加载了第一个用户的配置
    // 如果用户列表为空（没有用户），则加载管理员自己的配置
    if (!selectedViewUserId.value) {
      await loadConfigWithFallback(null)
    }
  } else {
    // ✅ 普通用户：优先从数据库加载任务配置（支持多设备同步）
    await loadConfigWithFallback(null)
  }
  
  // 恢复任务状态（搜索轮数、今日搜索次数等，但不恢复taskStatus，因为要从后端获取）
  loadStatusFromStorage()
  
  // ✅ 加载客户端列表到agentStore（用于判断可用客户端）
  try {
    const res = await getAgentClientList({ page_num: 1, page_size: 1000 })
    if (res.code === 200 && res.data && res.data.rows) {
      const agentStore = useAgentStore()
      agentStore.setClients(res.data.rows.map(client => ({
        ...client,
        client_type: client.client_type || '',
        online_status: client.online_status || 'offline',
        login_status: client.login_status || 'not_logged_in'
      })))
      console.log(`[SearchTask] 已加载 ${res.data.rows.length} 个客户端到agentStore`)
    }
  } catch (error) {
    console.error('[SearchTask] 加载客户端列表失败:', error)
  }
  
  // ✅ 加载最新搜索结果作为缓存（用于匹配新商品）
  await loadSearchResultsFromStorage()
  
  // ⚠️ 重要：先检查后端任务状态，确保状态同步（必须在所有状态恢复之前）
  // 这样可以确保前端状态与后端实际状态一致
  await updateTaskStatus()
  
  // 注意：updateTaskStatus() 内部已经根据后端状态启动了轮询，这里不需要再次检查
  // 但为了确保，如果状态是运行中但轮询未启动，再次启动
  if (taskStatus.value === 'running' && !statusTimer) {
    console.log('[SearchTask] 页面加载：任务正在运行，启动状态轮询')
  startStatusPolling()
  } else if (taskStatus.value === 'stopped' && statusTimer) {
    console.log('[SearchTask] 页面加载：任务已停止，停止状态轮询')
    stopStatusPolling()
  }
  
  // 连接WebSocket接收实时通知
  websocketManager.on(handleWSMessage)
  
  // ⚠️ 不再调用 handleRefreshResults()，避免清空已恢复的搜索结果
  // handleRefreshResults()  // 注释掉，保持历史数据可见
  
  // console.log('[SearchTask] 页面加载完成，当前任务状态:', taskStatus.value)  // 高频日志，已注释
})

onActivated(() => {
  // ✅ 页面被激活时（从其他页面切换回来）
  // 如果已经有数据显示，不重新加载（保留最新数据）
  // 如果没有数据，加载数据库数据作为初始显示
  if (!searchResults.value || searchResults.value.length === 0) {
    console.log('[SearchTask] 页面激活：无数据显示，加载数据库数据')
    loadSearchResultsFromStorage()
  } else {
    console.log(`[SearchTask] 页面激活：已有 ${searchResults.value.length} 条数据，保留显示`)
  }
  
  // 重新连接WebSocket（如果断开了）
  websocketManager.on(handleWSMessage)
  
  // 重新启动状态轮询（如果任务正在运行）
  if (taskStatus.value === 'running' && !statusTimer) {
    startStatusPolling()
  }
  
  // ✅ 如果是管理员模式，重新启动定时刷新
  if (isAdmin.value && selectedViewUserId.value && !adminRefreshTimer) {
    startAdminRefresh()
  }
})

onUnmounted(() => {
  // TODO: 断开WebSocket
  stopStatusPolling()
  stopAdminRefresh()  // ✅ 停止管理员模式的定时刷新
  websocketManager.off(handleWSMessage)
  // 清理日志自动刷新
  if (logAutoRefreshTimer) {
    clearInterval(logAutoRefreshTimer)
    logAutoRefreshTimer = null
  }
})

// ==================== 日志查看 ====================
const logDialogVisible = ref(false)
const logText = ref('')
const logLoading = ref(false)
const logFilter = ref('')
const logLines = ref(500)
const autoRefresh = ref(false)
const logContentRef = ref(null)
let logAutoRefreshTimer = null

// ✅ 修改：跳转到日志页面的实时日志tab
const router = useRouter()
function handleRealtimeLog() {
  router.push({
    path: '/agent/log-view',
    query: { tab: 'realtime' }
  })
}

// 保留旧的日志对话框功能（用于控制端日志，如果需要）
function showLogDialog() {
  logDialogVisible.value = true
  loadLogs()
}

async function loadLogs() {
  logLoading.value = true
  try {
    // 如果过滤条件为空字符串，则传递null
    const clientIdFilter = (logFilter.value && logFilter.value.trim()) || null
    const res = await getAgentLogs(clientIdFilter, logLines.value)
    if (res.code === 200 && res.data) {
      const logs = res.data.logs || []
      logText.value = logs.join('')
      // 自动滚动到底部
      nextTick(() => {
        if (logContentRef.value) {
          logContentRef.value.scrollTop = logContentRef.value.scrollHeight
        }
      })
    } else {
      ElMessage.error(res.msg || '获取日志失败')
      logText.value = ''
    }
  } catch (error) {
    console.error('加载日志失败:', error)
    ElMessage.error('加载日志失败：' + (error.message || '未知错误'))
    logText.value = ''
  } finally {
    logLoading.value = false
  }
}

function toggleAutoRefresh() {
  autoRefresh.value = !autoRefresh.value
  if (autoRefresh.value) {
    // 开始自动刷新，每3秒刷新一次
    logAutoRefreshTimer = setInterval(() => {
      loadLogs()
    }, 3000)
    ElMessage.success('已开启自动刷新')
  } else {
    // 停止自动刷新
    if (logAutoRefreshTimer) {
      clearInterval(logAutoRefreshTimer)
      logAutoRefreshTimer = null
    }
    ElMessage.info('已停止自动刷新')
  }
}

function downloadLogs() {
  if (!logText.value) {
    ElMessage.warning('没有日志可下载')
    return
  }
  const blob = new Blob([logText.value], { type: 'text/plain;charset=utf-8' })
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = `agent-logs-${new Date().toISOString().slice(0, 10)}.txt`
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)
  URL.revokeObjectURL(url)
  ElMessage.success('日志下载成功')
}

// ==================== WebSocket ====================
function handleWSMessage(payload) {
  if (!payload) return
  
  // ✅ 处理状态更新事件（更新agentStore，确保客户端列表和状态同步）
  if (payload.type === 'status_update' && payload.client_id && payload.data) {
    const agentStore = useAgentStore()
    // 查找现有客户端
    const existingClient = agentStore.clients.find(c => c.client_id === payload.client_id)
    
    // 处理 online_status（兼容两种格式）
    let onlineStatus = 'offline'
    if (payload.data.online_status) {
      onlineStatus = payload.data.online_status
    } else if ('online' in payload.data) {
      onlineStatus = payload.data.online ? 'online' : 'offline'
    }
    
    if (existingClient) {
      // 更新现有客户端状态（保留关键字段，合并新数据）
      Object.assign(existingClient, {
        ...payload.data,
        // 保留关键字段
        client_id: payload.client_id,
        client_name: existingClient.client_name || payload.data.client_name || existingClient.hostname || payload.client_id,
        client_type: payload.data.client_type || existingClient.client_type, // ✅ 使用合并后的client_type（从数据库读取）
        online_status: onlineStatus || existingClient.online_status || 'offline',
        login_status: payload.data.login_status || existingClient.login_status || 'not_logged_in'
      })
      console.debug('[SearchTask] 已更新客户端状态:', payload.client_id, {
        client_type: existingClient.client_type,
        online_status: existingClient.online_status,
        login_status: existingClient.login_status
      })
    } else {
      // 新客户端，添加到列表
      agentStore.updateClient({
        client_id: payload.client_id,
        ...payload.data,
        client_name: payload.data.client_name || payload.data.hostname || payload.client_id,
        client_type: payload.data.client_type || 'search', // ✅ 使用合并后的client_type
        online_status: onlineStatus,
        login_status: payload.data.login_status || 'not_logged_in'
      })
      console.log('[SearchTask] 已添加新客户端:', payload.client_id, {
        client_type: payload.data.client_type,
        online_status: onlineStatus,
        login_status: payload.data.login_status
      })
    }
    return
  }
  
  // 处理搜索结果消息
  // 注意：event可能在payload.event或payload.message.event中
  const event = payload.event || payload.message?.event
  if (payload.type === 'client_response' && event === 'search' && payload.message?.success) {
    const data = payload.message.data || {}
    // 处理后的数据格式：{keyword, results, new_items, total, filtered, new_count}
    // 注意：后端处理后的结果是 {results: [...], new_items: [...], keyword: '...', ...}
    // 兼容后端处理后的格式（results）和Agent原始格式（items）
    const items = data.results || data.items || []
    const keyword = data.keyword || taskConfig.keyword
    const now = new Date()
    lastSearchAt.value = now.toLocaleString()
    searchRounds.value += 1
    todaySearchCount.value += 1
    
    // 保存状态到localStorage（用于页面切换后恢复）
    saveStatusToStorage()
    
    console.log('[SearchTask] 收到搜索结果:', {
      keyword,
      itemsCount: items.length,
      total: data.total,
      filtered: data.filtered,
      newCount: data.new_count,
      hasResults: !!data.results,
      hasItems: !!data.items,
      resultsType: Array.isArray(data.results) ? 'array' : typeof data.results,
      itemsType: Array.isArray(data.items) ? 'array' : typeof data.items,
      dataKeys: Object.keys(data),
      messageKeys: Object.keys(payload.message || {}),
      payloadEvent: payload.event,
      messageEvent: payload.message?.event,
      processed: payload.message?.processed,
      // 完整的数据结构（用于调试）
      fullPayload: JSON.parse(JSON.stringify(payload)),
      fullData: JSON.parse(JSON.stringify(data))
    })
    
    // 额外的调试：如果results不存在，检查原始数据
    if (!data.results && !data.items && Object.keys(data).length > 0) {
      console.warn('[SearchTask] ⚠️ 搜索结果数据异常:', {
        dataKeys: Object.keys(data),
        dataSample: Object.keys(data).slice(0, 5).reduce((acc, key) => {
          acc[key] = typeof data[key] === 'object' ? '[object]' : String(data[key]).slice(0, 50)
          return acc
        }, {}),
        messageSuccess: payload.message?.success,
        messageProcessed: payload.message?.processed,
        messageDataType: typeof payload.message?.data
      })
    }
    
    if (Array.isArray(items) && items.length > 0) {
      const mapped = items.map(it => {
        // 兼容多种商品ID字段名：id / item_id / itemId
        const itemId = it.id || it.item_id || it.itemId || ''
        return {
        ...it,
          id: itemId,  // 统一使用 id 字段
          item_id: itemId,  // 保留 item_id 兼容性
        keyword,
        title: it.title || it.itemTitle || '',
        image_url: it.image_url || it.picUrl || it.pic_url || '',
        seller_nick: it.seller_nick || it.sellerNick || '',
          seller_id: it.seller_id || it.sellerId || '',  // ✅ 确保seller_id正确传递
        price: typeof it.price === 'number' ? it.price : Number(it.price) || 0,
          tagname: it.tagname || it.tagName || '',  // ✅ 商品标签（包邮/极好等）
          search_time: now.toLocaleString(),
          publish_time: it.publish_time || it.publishTime || '',
          is_new: data.new_items && Array.isArray(data.new_items) && data.new_items.some(ni => {
            // 兼容多种ID字段名
            const newItemId = ni.id || ni.item_id || ni.itemId || ''
            return newItemId && itemId && String(newItemId) === String(itemId)
          })
        }
      })
      
      // ✅ 判断是否有新商品
      const hasNewItems = data.new_items && Array.isArray(data.new_items) && data.new_items.length > 0
      
      // ✅ 获取本次搜索的新商品ID集合
      const newItemIds = new Set()
      if (hasNewItems && data.new_items) {
        data.new_items.forEach(newItem => {
          const itemId = newItem.id || newItem.item_id || newItem.itemId || ''
          if (itemId) {
            newItemIds.add(String(itemId))
          }
        })
      }
      
      if (hasNewItems) {
        // ✅ 有新商品时：清除所有现有商品的高亮（不管之前是否是新商品）
        searchResults.value.forEach(item => {
          item.is_new_highlight = false  // 清除所有高亮
          item.is_new = false  // 清除新商品标记
        })
        
        // ✅ 只标记本次搜索出的新商品为高亮
        mapped.forEach(item => {
          const itemId = String(item.id || item.item_id || '')
          if (newItemIds.has(itemId)) {
            item.is_new = true
            item.is_new_highlight = true  // 标记为需要高亮
          } else {
            item.is_new = false
            item.is_new_highlight = false  // 确保不是新商品的不高亮
          }
        })
      } else {
        // ✅ 没有新商品时，清除所有高亮（本次搜索没有新商品，不应该有任何高亮）
        searchResults.value.forEach(item => {
          item.is_new_highlight = false  // 清除所有高亮
        })
        
        // ✅ 也清除新结果中的高亮标记
        mapped.forEach(item => {
          item.is_new = false
          item.is_new_highlight = false
        })
      }
      
      // ✅ 合并新结果到列表前面，并去重（保留新结果的版本）
      // 过滤掉重复的商品（保留新结果，去除旧结果中的重复项）
      const filteredExisting = searchResults.value.filter(item => {
        const itemId = item.id || item.item_id || ''
        return !mapped.some(newItem => {
          const newItemId = newItem.id || newItem.item_id || ''
          return itemId && newItemId && String(itemId) === String(newItemId)
        })
      })
      
      // 合并并限制数量
      searchResults.value = [...mapped, ...filteredExisting].slice(0, Number(taskConfig.display_count) || 30)
      console.log(`[SearchTask] 已添加 ${mapped.length} 条搜索结果，当前总数: ${searchResults.value.length}`)
      
      // ✅ 保存搜索结果到 localStorage
      saveSearchResultsToStorage()
    } else {
      console.log('[SearchTask] 搜索结果为空或不是数组')
    }
  }
}
</script>

<style scoped>
.app-container {
  padding: 20px;
}

/* 新商品行高亮背景色 - 使用愉悦的薄荷绿色调，表示新鲜商品 */
:deep(.row-new-item) {
  background: linear-gradient(90deg, #d1fae5 0%, #a7f3d0 50%, #d1fae5 100%) !important;
  border-left: 4px solid #10b981 !important;
  animation: newItemHighlight 3s ease-in-out infinite;
  box-shadow: 0 2px 8px rgba(16, 185, 129, 0.2) !important;
}

:deep(.row-new-item:hover) {
  background: linear-gradient(90deg, #a7f3d0 0%, #6ee7b7 50%, #a7f3d0 100%) !important;
  box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3) !important;
}

/* ✅ 已下单商品特殊背景色 */
:deep(.row-ordered-item) {
  background-color: #f0fdf4 !important;
  border-left: 3px solid #10b981 !important;
}

:deep(.row-ordered-item:hover) {
  background-color: #dcfce7 !important;
}

/* 新商品高亮动画（闪烁提醒） - 使用愉悦的薄荷绿色调 */
@keyframes newItemHighlight {
  0% {
    background: linear-gradient(90deg, #d1fae5 0%, #a7f3d0 50%, #d1fae5 100%);
    box-shadow: 0 2px 8px rgba(16, 185, 129, 0.2);
  }
  50% {
    background: linear-gradient(90deg, #a7f3d0 0%, #6ee7b7 50%, #a7f3d0 100%);
    box-shadow: 0 4px 16px rgba(16, 185, 129, 0.4);
  }
  100% {
    background: linear-gradient(90deg, #d1fae5 0%, #a7f3d0 50%, #d1fae5 100%);
    box-shadow: 0 2px 8px rgba(16, 185, 129, 0.2);
  }
}

.mb-4 {
  margin-bottom: 16px;
}

.mt-4 {
  margin-top: 16px;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* ✅ 运行中动画样式 - 只保留搜索结果旁边的动画 */

/* 搜索结果标题旁 - 运行中徽章 */
.search-running-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: 12px;
  padding: 4px 12px;
  background: linear-gradient(135deg, #409EFF 0%, #66b1ff 100%);
  color: white;
  border-radius: 12px;
  font-size: 12px;
  font-weight: 500;
  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);
}

.search-running-icon {
  font-size: 14px;
  animation: rotate 1.5s linear infinite;
}

.search-running-text {
  animation: pulse 2s ease-in-out infinite;
}

@keyframes rotate {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

@keyframes pulse {
  0%, 100% {
    opacity: 1;
  }
  50% {
    opacity: 0.6;
  }
}

/* 日志查看器样式 */
.log-container {
  height: 600px;
  display: flex;
  flex-direction: column;
}

.log-toolbar {
  display: flex;
  align-items: center;
  margin-bottom: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid #e4e7ed;
}

.log-content {
  flex: 1;
  overflow: auto;
  background: #1e1e1e;
  border-radius: 4px;
  padding: 12px;
  font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
}

.log-text {
  margin: 0;
  color: #d4d4d4;
  font-size: 12px;
  line-height: 1.6;
  white-space: pre-wrap;
  word-wrap: break-word;
}

.log-empty {
  color: #909399;
  text-align: center;
  padding: 40px;
}
</style>

